package com.xbongbong.pay.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pay.pojo.PayHttpResponse;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 微信支付 http请求工具类
 * @author 魏荣杰
 * @date 2021/1/8 14:20
 * @since
 * @version
 */
public class PayHttpUtil {
    private static final Logger LOG = LoggerFactory.getLogger(PayHttpUtil.class);


    public static String mapToXml(Map<String, String> params) {
        return forEachMap(params, "<xml>", "</xml>").toString();
    }
    /**
     * 遍历 Map 并构建 xml 数据
     *
     * @param params 需要遍历的 Map
     * @param prefix xml 前缀
     * @param suffix xml 后缀
     * @return xml 字符串
     */
    public static StringBuffer forEachMap(Map<String, String> params, String prefix, String suffix) {
        StringBuffer xml = new StringBuffer();
        if (StringUtil.isNotEmpty(prefix)) {
            xml.append(prefix);
        }
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            // 略过空值
            if (StringUtil.isEmpty(value)) {
                continue;
            }
            xml.append("<").append(key).append(">");
            xml.append(entry.getValue());
            xml.append("</").append(key).append(">");
        }
        if (StringUtil.isNotEmpty(suffix)) {
            xml.append(suffix);
        }
        return xml;
    }

    public static CloseableHttpResponse doPost(CloseableHttpClient httpClient, String url, AbstractHttpEntity httpEntity, Map<String, String> headers) throws IOException {
        try {
            HttpPost httpPost = new HttpPost(url);

            if (Objects.nonNull(headers)) {
                headers.forEach(httpPost::setHeader);
            }
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
            httpPost.setConfig(requestConfig);
            httpPost.setEntity(httpEntity);

            return httpClient.execute(httpPost);
        } finally {
            if (Objects.nonNull(httpClient)) {
                httpClient.close();
            }
        }

    }

    public static PayHttpResponse post(CloseableHttpClient httpClient, String url, AbstractHttpEntity httpEntity, Map<String, String> headers) {
        PayHttpResponse payHttpResponse = new PayHttpResponse();

        HttpPost httpPost = new HttpPost(url);

        if (Objects.nonNull(headers)) {
            headers.forEach(httpPost::setHeader);
        }
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
        httpPost.setConfig(requestConfig);
        httpPost.setEntity(httpEntity);

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);

            int statusCode = response.getStatusLine().getStatusCode();

            JSONObject body = new JSONObject();
            if (Objects.equals(statusCode, 200)) {
                HttpEntity entity = response.getEntity();
                if (Objects.nonNull(entity)) {
                    String resultStr = EntityUtils.toString(entity, "utf-8");
                    body = JSON.parseObject(resultStr);
                }
            } if (Objects.equals(statusCode, 204)) {
                body = new JSONObject();
            } else {
                LOG.error("com.xbongbong.pay.utils.PayHttpUtil.post failed, statusCode = " + statusCode + " , body = " + JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect));
                HttpEntity entity = response.getEntity();
                if (Objects.nonNull(entity)) {
                    String resultStr = EntityUtils.toString(entity, "utf-8");
                    if (resultStr.contains("<xml>")) {
                        org.json.JSONObject jsonObject1 = XML.toJSONObject(resultStr);
                        body = JSON.parseObject(jsonObject1.toString());
                    } else {
                        body = JSON.parseObject(resultStr);
                    }
                }
            }
            payHttpResponse.setStatus(statusCode);
            payHttpResponse.setBody(body);
            payHttpResponse.setHeaders(response.getAllHeaders());
        } catch (IOException e) {
            LOG.error("com.xbongbong.pay.utils.PayHttpUtil.post failed", e);
        } finally {
            if (Objects.nonNull(httpClient)) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.pay.utils.PayHttpUtil.post client close failed", e);
                }
            }
            if (Objects.nonNull(response)) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.pay.utils.PayHttpUtil.post response close failed", e);
                }
            }
        }
        return payHttpResponse;
    }

    /**
     * Description: post请求（使用json）
     * @param httpClient
     * @param url
     * @param data
     * @param headers
     * @return com.alibaba.fastjson.JSONObject
     * @throws
     * @author 魏荣杰
     * @date 2021/1/11 14:33
     * @since
     */
    public static PayHttpResponse httpPostByJson(CloseableHttpClient httpClient, String url, Object data, Map<String, String> headers) {
        headers.put("Content-Type", "application/json");
        headers.put("Accept", "application/json");
        StringEntity stringEntity = new StringEntity(JSON.toJSONString(data), "utf-8");
        stringEntity.setContentType(ContentType.APPLICATION_JSON.toString());
        return post(httpClient, url, stringEntity, headers);
    }

    /**
     * Description: post请求（使用xml)
     * @param httpClient
     * @param url
     * @param data
     * @param headers
     * @return com.alibaba.fastjson.JSONObject
     * @throws
     * @author 魏荣杰
     * @date 2021/1/11 14:40
     * @since
     */
    public static PayHttpResponse httpPostByXml(CloseableHttpClient httpClient, String url, Object data, Map<String, String> headers) {
        headers.put("Content-Type", "text/xml; charset=UTF-8");
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(data));
        Map<String, String> param = new HashMap<>();
        jsonObject.forEach((k, v) -> param.put(k, v.toString()));
        StringEntity stringEntity = new StringEntity(mapToXml(param), "utf-8");
        return post(httpClient, url, stringEntity, headers);
    }


    public static PayHttpResponse get(CloseableHttpClient httpClient, String url, Object data, Map<String, String> headers) {
        PayHttpResponse payHttpResponse = new PayHttpResponse();
        CloseableHttpResponse response = null;
        try {
            URIBuilder uriBuilder = new URIBuilder(url);
            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(data));
            jsonObject.forEach((k, v) -> uriBuilder.setParameter(k, v.toString()));

            HttpGet httpGet = new HttpGet(uriBuilder.build());
            if (Objects.nonNull(headers)) {
                headers.forEach(httpGet::setHeader);
            }
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
            httpGet.setConfig(requestConfig);

            response = httpClient.execute(httpGet);

            JSONObject body = new JSONObject();
            int statusCode = response.getStatusLine().getStatusCode();
            if (Objects.equals(statusCode, 200)) {
                HttpEntity entity = response.getEntity();
                if (Objects.nonNull(entity)) {
                    String resultStr = EntityUtils.toString(entity, "utf-8");
                    body = JSON.parseObject(resultStr);
                }
            } if (Objects.equals(statusCode, 204)) {
                body = new JSONObject();
            } else {
                LOG.error("com.xbongbong.pay.utils.PayHttpUtil.get failed, statusCode = " + statusCode + " , body = " + JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect));
                HttpEntity entity = response.getEntity();
                if (Objects.nonNull(entity)) {
                    String resultStr = EntityUtils.toString(entity, "utf-8");
                    body = JSON.parseObject(resultStr);
                }
            }

            payHttpResponse.setStatus(statusCode);
            payHttpResponse.setHeaders(response.getAllHeaders());
            payHttpResponse.setBody(body);
        } catch (URISyntaxException | IOException e) {
            LOG.error("com.xbongbong.pay.utils.PayHttpUtil.get failed", e);
        } finally {
            if (Objects.nonNull(httpClient)) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.pay.utils.PayHttpUtil.get close failed", e);
                }
            }
            if (Objects.nonNull(response)) {
                try {
                    response.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.pay.utils.PayHttpUtil.get close failed", e);
                }
            }
        }
        return payHttpResponse;
    }
    /**
     * Description: get请求（使用json）
     * @param httpClient
     * @param url
     * @param data
     * @param headers
     * @return com.alibaba.fastjson.JSONObject
     * @throws
     * @author 魏荣杰
     * @date 2021/1/11 14:33
     * @since
     */
    public static PayHttpResponse httpGetByJson(CloseableHttpClient httpClient, String url, Object data, Map<String, String> headers) {
        headers.put("Accept", "application/json");
        return get(httpClient, url, data, headers);
    }
}
